package com.zdw.demo.controller;

import com.zdw.common.parent.JSONResult;
import com.zdw.demo.dto.CustomerSelectDto;
import com.zdw.demo.config.international.InternationalUtils;
import io.swagger.annotations.ApiOperation;
import lombok.Getter;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * <p>
 * 反射机制 前端控制器
 * </p>
 *
 * @author 卓德文
 * @since 2023-05-18
 */
@RestController
@RequestMapping("/reflect")
public class ReflectController {

    /**
     * 反射构造方法,并调用构造方法获取实例
     *
     * @return
     */
    @PostMapping("/reflectConstructor")
    @ApiOperation("反射构造方法,并调用构造方法获取实例")
    public JSONResult reflectConstructor() {
        try {
            //1.获取字节码对象
            //1.1.方式一
            Class<?> customerClass1 = Class.forName("com.zdw.demo.dto.CustomerSelectDto");
            //1.2.方式二
            CustomerSelectDto customerSelectDto = new CustomerSelectDto();
            Class<?> customerClass2 = customerSelectDto.getClass();
            //1.3.同一个类在JVM中只有一份字节码对象
            System.out.println("同一个类在JVM中只有一份字节码对象:" + (customerClass1 == customerClass2));

            //2.反射获取构造方法(使用Class类的方法),并调用构造方法(使用Construcor类的方法)
            //2.1.获取构造方法
            //2.1.1.获取所有public构造器
            Constructor<?>[] publicConstructors = customerClass1.getConstructors();
            //2.1.2.获取指定的public构造器
            Constructor<?> publicConstructor = customerClass1.getConstructor(String.class);
            //2.1.3.获取所有构造器
            Constructor<?>[] declaredConstructors = customerClass1.getDeclaredConstructors();
            //2.1.4.获取指定的一个构造器
            Constructor<?> declaredConstructor = customerClass1.getDeclaredConstructor(String.class);

            //2.2.反射调用构造方法
            Object instance = declaredConstructor.newInstance("卓德文");
            System.out.println("反射构造方法,实例类型:" + instance.getClass());
        } catch (Exception e) {
            return new JSONResult().markSuccess(InternationalUtils.getInternational("common.fail"), null);
        }
        return new JSONResult().markSuccess(InternationalUtils.getInternational("common.success"), null);
    }

    /**
     * 反射方法,并用实例调用方法获取结果
     *
     * @return
     */
    @PostMapping("/reflectMethod")
    @ApiOperation("反射方法,并用实例调用方法获取结果")
    public JSONResult reflectMethod() {
        try {
            //1.获取字节码对象
            //1.1.方式一
            Class<?> customerClass1 = Class.forName("com.zdw.demo.dto.CustomerSelectDto");

            //2.反射获取构造方法(使用Class类的方法),并调用构造方法(使用Construcor类的方法)
            Constructor<?> declaredConstructor = customerClass1.getDeclaredConstructor(String.class);
            Object instance = declaredConstructor.newInstance("哈哈");

            //3.反射获取类中的方法(使用Class类中的方法),并调用方法(使用Method类中的方法)
            //3.1.反射获取类中的方法
            //3.1.1.获取全部public方法(包含继承而来的)
            Method[] methods1 = customerClass1.getMethods();
            StringBuilder sb1 = new StringBuilder();
            for (Method method : methods1) {
                sb1.append(method.getName()).append(";");
            }
            System.out.println("全部public方法(包含继承而来的)" + sb1);
            //3.1.2.获取指定的一个public方法(包含继承而来的)
            Method exportName1 = customerClass1.getMethod("exportName", String.class);
            System.out.println("获取指定的一个public方法(包含继承而来的)" + exportName1);
            //3.1.3.获取所有自身的方法(不包含继承而来的)
            Method[] methods2 = customerClass1.getDeclaredMethods();
            StringBuilder sb2 = new StringBuilder();
            for (Method method : methods2) {
                sb2.append(method.getName()).append(";");
            }
            System.out.println("获取所有自身的方法(不包含继承而来的)" + sb2);
            //3.1.4.获取指定的一个方法(不包含继承而来的)
            Method exportName2 = customerClass1.getDeclaredMethod("exportName", String.class);
            System.out.println("获取指定的一个方法(不包含继承而来的)" + exportName2);

            //3.2.反射调用方法(注意:invoke方法用method实例调用,其中入参1是类的实例对象,入参2是方法实际入参)
            Object invokeStr = exportName2.invoke(instance, "卓德文");
            System.out.println(invokeStr);

        } catch (Exception e) {
            return new JSONResult().markSuccess(InternationalUtils.getInternational("common.fail"), null);
        }
        return new JSONResult().markSuccess(InternationalUtils.getInternational("common.success"), null);
    }

    /**
     * 反射获取注解
     *
     * @return
     */
    @PostMapping("/reflectAnnotation")
    @ApiOperation("反射获取注解")
    public JSONResult reflectAnnotation() {
        try {
            //1.获取字节码对象
            //1.1.方式一
            Class<?> customerClass1 = Class.forName("com.zdw.demo.dto.CustomerSelectDto");

            //2.获取注解
            //2.1.获取类上所有注解
            Annotation[] annotations = customerClass1.getAnnotations();
            //2.2.获取类上指定注解
            Getter getter = customerClass1.getAnnotation(Getter.class);

        } catch (Exception e) {
            return new JSONResult().markSuccess(InternationalUtils.getInternational("common.fail"), null);
        }
        return new JSONResult().markSuccess(InternationalUtils.getInternational("common.success"), null);
    }

    //主方法测试
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //1.获取字节码对象
        //1.1.方式一
        Class<?> customerClass1 = Class.forName("com.zdw.demo.dto.CustomerSelectDto");
        //1.2.方式二
        CustomerSelectDto customerSelectDto = new CustomerSelectDto();
        Class<?> customerClass2 = customerSelectDto.getClass();
        //1.3.同一个类在JVM中只有一份字节码对象
        System.out.println("同一个类在JVM中只有一份字节码对象:" + (customerClass1 == customerClass2));


        //2.反射获取构造方法(使用Class类的方法),并调用构造方法(使用Construcor类的方法)
        //2.1.获取构造方法
        //2.1.1.获取所有public构造器
        Constructor<?>[] publicConstructors = customerClass1.getConstructors();
        //2.1.2.获取指定的public构造器
        Constructor<?> publicConstructor = customerClass1.getConstructor(String.class);
        //2.1.3.获取所有构造器
        Constructor<?>[] declaredConstructors = customerClass1.getDeclaredConstructors();
        //2.1.4.获取指定的一个构造器
        Constructor<?> declaredConstructor = customerClass1.getDeclaredConstructor(String.class);

        //2.2.反射调用构造方法
        Object instance = declaredConstructor.newInstance("卓德文");
        System.out.println("反射构造方法,实例类型:" + instance.getClass());


        //3.反射获取类中的方法(使用Class类中的方法),并调用方法(使用Method类中的方法)
        //3.1.反射获取类中的方法
        //3.1.1.获取全部public方法(包含继承而来的)
        Method[] methods1 = customerClass1.getMethods();
        StringBuilder sb1 = new StringBuilder();
        for (Method method : methods1) {
            sb1.append(method.getName()).append(";");
        }
        System.out.println("全部public方法(包含继承而来的)" + sb1);
        //3.1.2.获取指定的一个public方法(包含继承而来的)
        Method exportName1 = customerClass1.getMethod("exportName", String.class);
        System.out.println("获取指定的一个public方法(包含继承而来的)" + exportName1);
        //3.1.3.获取所有自身的方法(不包含继承而来的)
        Method[] methods2 = customerClass1.getDeclaredMethods();
        StringBuilder sb2 = new StringBuilder();
        for (Method method : methods2) {
            sb2.append(method.getName()).append(";");
        }
        System.out.println("获取所有自身的方法(不包含继承而来的)" + sb2);
        //3.1.4.获取指定的一个方法(不包含继承而来的)
        Method exportName2 = customerClass1.getDeclaredMethod("exportName", String.class);
        System.out.println("获取指定的一个方法(不包含继承而来的)" + exportName2);

        //3.2.反射调用方法
        Object invokeStr = exportName2.invoke(instance, "卓德文");
        System.out.println(invokeStr);


        //4.反射获取注解
        //4.1.获取类上所有注解
        Annotation[] annotations = customerClass1.getAnnotations();
        System.out.println(annotations);
        //4.2.获取类上指定注解
        Getter getter = customerClass1.getAnnotation(Getter.class);
        System.out.println(getter);
    }

}
